package com.kuaishou.locallife.open.api.client.oauth;

import java.io.IOException;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import com.kuaishou.locallife.open.api.KsLocalLifeApiException;
import com.kuaishou.locallife.open.api.common.Constants;
import com.kuaishou.locallife.open.api.common.Constants.ContentType;
import com.kuaishou.locallife.open.api.common.dto.KsHttpResponseDTO;
import com.kuaishou.locallife.open.api.common.http.HttpClient;
import com.kuaishou.locallife.open.api.common.http.net.KsJdkHttpClient;
import com.kuaishou.locallife.open.api.common.utils.GsonUtils;
import com.kuaishou.locallife.open.api.common.utils.KsStringUtils;
import com.kuaishou.locallife.open.api.common.utils.LoggerUtils;
import com.kuaishou.locallife.open.api.common.utils.RequestCheckUtils;
import com.kuaishou.locallife.open.api.response.oauth.KsAccessTokenPreviousVersionResponse;

/**
 * @author shuxiaohui <shuxiaohui@kuaishou.com>
 * Created on 2020-04-09
 */
public class OAuthAccessTokenKsClient {
    protected static final Logger logger = Logger.getLogger(OAuthAccessTokenKsClient.class.getName());

    // appKey
    protected String appKey;
    // appSecret
    protected String appSecret;
    // api链接超时(ms)

    // contentType
    protected String contentType;

    protected int connectTimeout;
    // api接口读超时(ms)
    protected int readTimeout;
    // api代理
    private Proxy proxy;

    private HttpClient httpClient;

    public OAuthAccessTokenKsClient(String appKey, String appSecret) {
        this.appKey = appKey;
        this.appSecret = appSecret;
        this.connectTimeout = 15000;
        this.readTimeout = 30000;
        this.init();
    }

    public OAuthAccessTokenKsClient(String appKey, String appSecret, String contentType, int connectTimeout, int readTimeout) {
        this(appKey, appSecret);
        this.contentType = KsStringUtils.isBlank(this.contentType)
                ? ContentType.JSON
                : contentType;
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.init();
    }

    /**
     * 获取授权access_token
     *
     * @param code 授权码
     * @return access_token
     * @throws KsLocalLifeApiException api调用异常
     */
    public KsAccessTokenPreviousVersionResponse getAccessToken(String code) throws KsLocalLifeApiException {
        RequestCheckUtils.checkNotEmpty(appKey, "appKey");
        RequestCheckUtils.checkNotEmpty(appSecret, "appSecret");

        try {
            // 获取access_token
            KsHttpResponseDTO httpResponseDTO = this.httpClient.doGet(Constants.Oauth.OAUTH_ACCESS_TOKEN_URL, null,
                    buildOauthAccessTokenRequest(code), this.getProxy());

            KsAccessTokenPreviousVersionResponse
                    response = GsonUtils.fromJSON(httpResponseDTO.getBody(), KsAccessTokenPreviousVersionResponse.class);
            if (response == null) {
                throw new KsLocalLifeApiException("ks oauth access_token api responseBody parse fail");
            }
            return response;
        } catch (IOException e) {
            LoggerUtils.logApiError(logger, appKey, "ks.oauth.access.token",
                    Constants.Oauth.OAUTH_ACCESS_TOKEN_URL, null, e);
            throw new KsLocalLifeApiException(e);
        }
    }

    /**
     * 刷新授权access_token
     *
     * @param refreshToken 刷新token
     * @return access_token
     * @throws KsLocalLifeApiException api调用异常
     */
    public KsAccessTokenPreviousVersionResponse refreshAccessToken(String refreshToken) throws KsLocalLifeApiException {
        RequestCheckUtils.checkNotEmpty(appKey, "appKey");
        RequestCheckUtils.checkNotEmpty(appSecret, "appSecret");

        try {
            // 刷新access_token
            KsHttpResponseDTO httpResponseDTO = this.httpClient.doGet(Constants.Oauth.OAUTH_REFRESH_TOKEN_URL, null,
                    buildOauthRefreshTokenRequest(refreshToken), this.getProxy());

            KsAccessTokenPreviousVersionResponse
                    response = GsonUtils.fromJSON(httpResponseDTO.getBody(), KsAccessTokenPreviousVersionResponse.class);
            if (response == null) {
                throw new KsLocalLifeApiException("ks oauth refresh_token api responseBody parse fail");
            }
            return response;
        } catch (IOException e) {
            LoggerUtils.logApiError(logger, appKey, "ks.oauth.refresh.token",
                    Constants.Oauth.OAUTH_ACCESS_TOKEN_URL, null, e);
            throw new KsLocalLifeApiException(e);
        }
    }

    private Map<String, String> buildOauthAccessTokenRequest(String code) {
        Map<String, String> requestParams = new HashMap<String, String>();

        // 授权token相关请求参数
        requestParams.put("app_id", this.getAppKey());
        requestParams.put("app_secret", this.getAppSecret());
        requestParams.put("grant_type", Constants.Oauth.OAUTH_GRANT_TYPE_CODE);
        requestParams.put("code", code);

        return requestParams;
    }

    private Map<String, String> buildOauthRefreshTokenRequest(String refreshToken) {
        Map<String, String> requestParams = new HashMap<String, String>();

        // 授权token相关请求参数
        requestParams.put("app_id", this.getAppKey());
        requestParams.put("app_secret", this.getAppSecret());
        requestParams.put("grant_type", Constants.Oauth.OAUTH_GRANT_TYPE_REFRESH_TOKEN);
        requestParams.put("refresh_token", refreshToken);

        return requestParams;
    }

    public String getAppKey() {
        return appKey;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public void setAppSecret(String appSecret) {
        this.appSecret = appSecret;
    }

    public int getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public int getReadTimeout() {
        return readTimeout;
    }

    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    public Proxy getProxy() {
        return proxy;
    }

    public void setProxy(Proxy proxy) {
        this.proxy = proxy;
    }

    private void init() {
        initHttpClient();
    }

    private void initHttpClient() {
        if (this.httpClient == null) {
            this.httpClient = new KsJdkHttpClient.Builder().build();
        }
    }

    public HttpClient getHttpClient() {
        return httpClient;
    }

    public void setHttpClient(HttpClient httpClient) {
        this.httpClient = httpClient;
    }
}
